/**
 * UIPrefab转代码
 */

using GameUnityFramework.UIView;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using GameLogic.AbilitySystem;
using GameLogic.AbilitySystem.Attribute;
using GameBaseFramework.Base;
using GameBaseFramework.Attribute;

namespace Editor.AttributeSetGenerate
{
    public class AttributeSetGenerate
    {
        /// <summary>
        /// 代码导出路径
        /// </summary>
        public static string CodeGenerateExportPath = "Scripts/GameLogic/Gameplay/Attribute/AttributeSet";

        private static SerializedProperty sp;

        [MenuItem("Assets/AbilitySystem/AttributeSetGenerate")]
        public static void Generate()
        {
            GenerateFunction();
        }

        /// <summary>
        /// 生成函数名和Using
        /// </summary>
        private static void GenerateFunction()
        {
            var baseAttributeSet = ScriptableObject.CreateInstance(typeof(BaseAttributeSet));
            SerializedObject serializedObject = new SerializedObject(baseAttributeSet);
            sp = serializedObject.GetIterator();
            var sb = new StringBuilder();
            sb.Append(LineText("/**"));
            sb.Append(LineText(" * AutoGenerated Code By AttributeSetGenerate"));
            sb.Append(LineText(" */\n"));
            sb.Append(LineText("using UnityEngine;"));
            sb.Append(LineText("using System.Collections.Generic;"));
            sb.Append(LineText("using System.Linq;"));
            sb.Append(LineText("using GameBaseFramework.Attribute;\n"));
            sb.Append(LineText("namespace GameLogic.AbilitySystem.Attribute"));
            sb.Append(LineText("{"));
            sb.Append(LineText("public class CharacterAttributeSet : BaseAttributeSet", 1));
            sb.Append(LineText("{", 1));
            //构造函数
            sb.Append(LineText("CharacterAttributeSet()", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("AttributesDic = new(); ", 3));
            do
            {
                if (sp.type == "IntAttribute" || sp.type.Contains("Attribute"))
                {
                    sb.Append(LineText($"AttributesDic.Add(\"{sp.name}\", {sp.name}); ", 3));
                    sb.Append(LineText($"{sp.name}.OnCurrentValueChange.AddListener(On{sp.name}CurrentValueChange);", 3));
                }
            } while (sp.Next(true));
            sb.Append(LineText("}", 2));
            //回调
            baseAttributeSet = ScriptableObject.CreateInstance(typeof(BaseAttributeSet));
            serializedObject = new SerializedObject(baseAttributeSet);
            sp = serializedObject.GetIterator();
            do
            {
                if (sp.type.Contains("Attribute"))
                {
                    sb.Append(LineText($"public void On{sp.name}CurrentValueChange(float Value)", 2));
                    sb.Append(LineText("{\n", 2));
                    sb.Append(LineText("}", 2));
                }
            } while (sp.Next(true));
            //重载操作符
            //>和<
            sb.Append(LineText("public static bool operator >(CharacterAttributeSet a1, CharacterAttributeSet a2)", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("List<FloatAttribute> attributes1 = a1.Get();", 3));
            sb.Append(LineText("List<FloatAttribute> attributes2 = a2.Get();", 3));
            sb.Append(LineText("for (int i = 0; i < attributes1.Count; i++) ", 3));
            sb.Append(LineText("{", 3));
            sb.Append(LineText("if (attributes1[i] < attributes2[i]) return false; ", 4));
            sb.Append(LineText("}", 3));
            sb.Append(LineText("return true;", 3));
            sb.Append(LineText("}\n", 2));
            sb.Append(LineText("public static bool operator <(CharacterAttributeSet a1, CharacterAttributeSet a2)", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("List<FloatAttribute> attributes1 = a1.Get();", 3));
            sb.Append(LineText("List<FloatAttribute> attributes2 = a2.Get();", 3));
            sb.Append(LineText("for (int i = 0; i < attributes1.Count; i++) ", 3));
            sb.Append(LineText("{", 3));
            sb.Append(LineText("if (attributes1[i] > attributes2[i]) return false; ", 4));
            sb.Append(LineText("}", 3));
            sb.Append(LineText("return true;", 3));
            sb.Append(LineText("}\n", 2));

            //Get
            sb.Append(LineText("public List<FloatAttribute> Get()", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("return AttributesDic?.Values.ToList(); \n", 3));
            sb.Append(LineText("}", 2));

            //Set
            sb.Append(LineText("public void Set(List<FloatAttribute> attributes)", 2));
            sb.Append(LineText("{", 2));
            baseAttributeSet = ScriptableObject.CreateInstance(typeof(BaseAttributeSet));
            serializedObject = new SerializedObject(baseAttributeSet);
            sp = serializedObject.GetIterator();
            int AttributeCount = 0;
            do
            {
                DebugTool.Log(sp.name + "\n");
                if (sp.type.Contains("Attribute"))
                {
                    sb.Append(LineText($"{sp.name} = attributes[{AttributeCount++}]; ", 3));
                }
            } while (sp.Next(true));
            sb.Append(LineText("}", 2));

            //SetAttribute
            sb.Append(LineText("public void SetAttribute(string AttributeName, float f)", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("if (AttributesDic.TryGetValue(AttributeName, out var value))", 3));
            sb.Append(LineText("{", 3));
            sb.Append(LineText("value.BaseValue = f;", 4));
            sb.Append(LineText("}", 3));
            sb.Append(LineText("}\n", 2));

            //SetAttributeBuff
            sb.Append(LineText("public void SetAttributeBuff(string AttributeName, float slope, float intercept)", 2));
            sb.Append(LineText("{", 2));
            sb.Append(LineText("if (AttributesDic.TryGetValue(AttributeName, out var value))", 3));
            sb.Append(LineText("{", 3));
            sb.Append(LineText("value.ValueFunction.Set(slope, intercept);", 4));
            sb.Append(LineText("}", 3));
            sb.Append(LineText("}", 2));

            sb.Append(LineText("}", 1));
            sb.Append(LineText("}", 0));
            var dirPath = Path.Combine(Application.dataPath, CodeGenerateExportPath);
            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            var baseCodePath = Path.Combine(dirPath, $"CharacterAttributeSet.cs");
            File.WriteAllText(baseCodePath, sb.ToString());
        }

        public static string LineText(string text, int tabCount = 0)
        {
            string result = "";
            for (int i = 1; i <= tabCount; i++)
            {
                result = "\t" + result;
            }
            return result + text + "\n";
        }


    }
}